#include "bsp_ec800m.h"
#include "core_delay.h"
#include "string.h"
#include "stdio.h"
#include "bsp_usart.h"
#include "watchdog.h"
#include "bsp_led.h"
#include "../util/timedate.h"
#include "./lcd/bsp_ili9341_lcd.h"

char *strx,*extstrx;

CSTX_4G CSTX_4G_Status;	//模块的状态信息
int  errcount=0;	//失败次数 防止死循环
char ATSTR[BUFLEN];	//组建AT命令的函数
UART_BUF EC800M_BUF;

/* 简单的 IPv4 格式判断（用于日志打印，不影响功能）
 * 仅判断形如 d.d.d.d，且每段 0-255
 */
static int EC800M_IsIPv4(const char* s)
{
    if (!s) return 0;
    int d, cnt = 0;
    const char* p = s;
    while (*p)
    {
        if (sscanf(p, "%d", &d) != 1) return 0;
        if (d > 255 || d < 0) return 0;
        cnt++;
        // 移动到下一个分段或字符串末尾
        while (*p >= '0' && *p <= '9') p++;
        if (*p == '\0') break;
        if (*p != '.') return 0;
        p++;
    }
    return cnt == 4;
}

// 通用AT命令发送和响应检查函数
static char* EC800M_SendATCommandAndWaitForResponse(const char* command, const char* expected_response, int delay_ms, int max_retries)
{
    int retry_count = 0;
    char* response = NULL;
    
    while (retry_count < max_retries)
    {
        Clear_Buffer();
        EC800M_UART_SendStr((char*)command);
        Delay_ms(delay_ms);
        
        if (expected_response) {
            response = strstr((const char*)EC800M_BUF.buf, expected_response);
            if (response) {
                break;
            }
        } else {
            // 如果没有指定期望响应，直接返回
            response = EC800M_BUF.buf;
            break;
        }
        
        retry_count++;
        IWDG_ReloadCounter(); // 喂狗
    }
    
    return response;
}

// 通用重试函数
static int EC800M_RetryOperation(int (*operation)(void), int max_retries)
{
    int retry_count = 0;
    int result = 0;
    
    while (retry_count < max_retries) {
        result = operation();
        if (result) {
            break;
        }
        retry_count++;
        IWDG_ReloadCounter(); // 喂狗
    }
    
    return result;
}

/*****************************************************
服务器地址配置
- SERVERIP 可填写"域名"或"IPv4 地址"，二者皆可。
  例如：
    域名: "iot.example.com"
    IPv4: "123.207.210.43"
- 切换域名/IP 时，只需修改 SERVERIP；端口在 SERVERPORT 配置。
*****************************************************/
//#define SERVERIP "123.207.210.43"
//#define SERVERPORT 8888

//#define SERVERIP "83l6076j43.goho.co"
//#define SERVERPORT 17384

#define SERVERIP "129.211.174.224"
#define SERVERPORT 5844

//初始化IO 串2
//bound:波特率
void EC800M_UART_Init()
{
    u32 bound = 115200;
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
     
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//使能，GPIOA时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//USART2
    USART_DeInit(USART2);  //复位串口2
    //USART2_TX   PA.2
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA2
   
    //USART2_RX	  PA.3
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);  //初始化PA3

    //Usart1 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级0
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;		//子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
  
    //USART 初始化设置
    USART_InitStructure.USART_BaudRate = bound;//115200
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
    USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式
    USART_Init(USART2, &USART_InitStructure); //初始化串口
    
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启接收中断
    USART_ITConfig(USART2, USART_IT_IDLE, ENABLE); //开启空闲中断
    USART_Cmd(USART2, ENABLE);                    //使能串口 
}

/*****************************************************
清空模块反馈的信息
*****************************************************/
void Clear_Buffer(void)//清空缓存
{
    EC800M_BUF.index=0;
    memset(EC800M_BUF.buf,0,BUFLEN);
    IWDG_ReloadCounter();//喂狗
}

// 检查SIM卡的辅助函数
static int check_sim_card(void)
{
    Clear_Buffer();
    EC800M_UART_SendStr("AT+CIMI\r\n");//获取卡号，类似是否存在卡的意思，比较重要。
    Delay_ms(500);
    return (strstr((const char*)EC800M_BUF.buf, "460") != NULL); //返回460，表明识别到卡了
}

// 检查网络激活状态的辅助函数
static int check_network_activation(void)
{
    Clear_Buffer();
    EC800M_UART_SendStr("AT+CGATT?\r\n");//查询激活状态
    Delay_ms(500);
    return (strstr((const char*)EC800M_BUF.buf, "+CGATT: 1") != NULL); //返1
}

// 检查信号质量的辅助函数
static void check_signal_quality(void)
{
    Clear_Buffer();
    EC800M_UART_SendStr("AT+CSQ\r\n");//查看获取CSQ值
    Delay_ms(300);
    strx = strstr((const char*)EC800M_BUF.buf, "+CSQ:");//返回CSQ
    if(strx)
    {
        printf("信号质量是:%s 注意：信号最大值是31 \r\n", EC800M_BUF.buf+14);      
    }
}

/*****************************************************
初始化模块 和单片机连接，获取卡号和信号质量
*****************************************************/
void EC800M_4G_Init(void)
{
    const int max_retries = 10;  // 最大重试次数
    
    //打印初始化信息
    printf("start init EC800M\r\n");
    
    // 发第一个命令ATE1
    strx = EC800M_SendATCommandAndWaitForResponse("ATE1\r\n", "OK", 300, max_retries);
    if (!strx) {
        printf("EC800M模块连接失败，已达到最大重试次数\r\n");
        return;  // 连接失败，退出初始化
    }
    
    printf("****单片机和模块连接成功*****\r\n");
    
    // 获取模块的版本
    EC800M_SendATCommandAndWaitForResponse("ATI\r\n", NULL, 300, 1);
    
    // 检查SIM卡
    if (!EC800M_RetryOperation(check_sim_card, max_retries)) {
        printf("SIM卡检测失败，请检查SIM卡是否正确插入\r\n");
        return;
    }
    
    printf("我的卡号是 : %s \r\n", EC800M_BUF.buf+8);
    
    // 检查网络激活状态
    if (!EC800M_RetryOperation(check_network_activation, max_retries)) {
        printf("网络激活失败，请检查网络信号\r\n");
        return;
    }
    
    // 检查信号质量
    check_signal_quality();
}

/*****************************************************
关闭之前存在的和服务器的链接 可能反馈失败 
*****************************************************/
void CSTX_4G_ConTCP(void)
{		
    //关闭之前建立的链接
    EC800M_UART_SendStr("AT+QICLOSE=0\r\n");//关闭socekt连接
    Delay_ms(100);
    EC800M_UART_SendStr("AT+QICLOSE=1\r\n");//关闭socekt连接
    Delay_ms(100);
    EC800M_UART_SendStr("AT+QICLOSE=2\r\n");//关闭socekt连接
    Delay_ms(100);
    
    Clear_Buffer();
    IWDG_ReloadCounter();//喂狗
}

/*****************************************************
确保PDP激活与APN配置（中国移动默认APN: cmnet）
返回值：1=就绪，0=失败
*****************************************************/
static int EC800M_EnsurePDP(void)
{
    int i;

    // 1) 确保已附着 CGATT=1
    for (i = 0; i < 10; i++)
    {
        Clear_Buffer();
        EC800M_UART_SendStr("AT+CGATT?\r\n");
        Delay_ms(300);
        strx = strstr((const char*)EC800M_BUF.buf, (const char*)"+CGATT: 1");
        if (strx) break;
        Delay_ms(200);
    }
    if (!strx) {
        printf("CGATT未就绪\r\n");
        return 0;
    }

    // 2) 设置APN（容错处理：任意一步OK即可，不因ERROR而失败）
    Clear_Buffer();
    EC800M_UART_SendStr("AT+CGDCONT=1,\"IP\",\"cmnet\"\r\n");
    Delay_ms(300);

    Clear_Buffer();
    EC800M_UART_SendStr("AT+QCGDEFCONT=\"IP\",\"cmnet\"\r\n");
    Delay_ms(300);

    // 3) 先去激活，再激活
    Clear_Buffer();
    EC800M_UART_SendStr("AT+QIDEACT=1\r\n");
    Delay_ms(300);

    // 4) 激活QIACT=1，带重试
    for (i = 0; i < 10; i++)
    {
        Clear_Buffer();
        EC800M_UART_SendStr("AT+QIACT=1\r\n");
        Delay_ms(500);
        // 检查OK
        strx = strstr((const char*)EC800M_BUF.buf, (const char*)"OK");
        if (strx) break;
        Delay_ms(200);
    }
    if (!strx) {
        printf("QIACT激活失败\r\n");
        return 0;
    }

    // 5) 通过 CGPADDR=1 检查是否获得 IP
    for (i = 0; i < 10; i++)
    {
        Clear_Buffer();
        EC800M_UART_SendStr("AT+CGPADDR=1\r\n");
        Delay_ms(300);
        // 期望: +CGPADDR: 1,"x.x.x.x"
        strx = strstr((const char*)EC800M_BUF.buf, (const char*)"+CGPADDR: 1,");
        if (strx) {
            printf("PDP已激活: %s\r\n", EC800M_BUF.buf);
            return 1;
        }
        Delay_ms(200);
    }

    printf("未获取到IP地址\r\n");
    return 0;
}

/*****************************************************
断线重连：关闭旧连接 -> 短延时 -> 重新建链
*****************************************************/
static void EC800M_Reconnect(void)
{
    LED_RED;  // 未连接时亮红灯
    printf("检测到断链，开始重连...\r\n");
    CSTX_4G_ConTCP();
    Delay_ms(200);
    CSTX_4G_CreateTCPSokcet();
}

void CSTX_4G_CreateTCPSokcet(void)//创建sokcet
{
    if(!EC800M_EnsurePDP()){
        printf("PDP未就绪，取消建链");
        return;
    }
    // QIOPEN 支持域名与 IPv4，此处仅做日志区分，实际连接统一走 QIOPEN
    if (EC800M_IsIPv4(SERVERIP)) {
        printf("使用IPv4地址连接: %s:%d", SERVERIP, SERVERPORT);
    } else {
        printf("使用域名连接: %s:%d", SERVERIP, SERVERPORT);
    }

    memset(ATSTR,0,BUFLEN);
    sprintf(ATSTR,"AT+QIOPEN=1,0,\"TCP\",\"%s\",%d,0,1\r\n",SERVERIP,SERVERPORT);
    EC800M_UART_SendStr(ATSTR);//创建连接TCP,输入IP以及服务器端口号码 
    Delay_ms(300);
    strx=strstr((const char*)EC800M_BUF.buf,(const char*)"+QIOPEN: 0,0");//检查是否登陆成功
    errcount=0;
    while(strx==NULL)
    {
        errcount++;
        strx=strstr((const char*)EC800M_BUF.buf,(const char*)"+QIOPEN: 0,0");//检查是否登陆成功
        Delay_ms(100);
        if(errcount>100)     //超时退出死循环 表示服务器连接失败
        {
            errcount = 0;
            break;
        }
    }  
    
    // 检查TCP连接是否成功
    if(strx != NULL) {
        printf("TCP连接成功\r\n");
        Delay_ms(10);
        LED_GREEN;  // 连接成功时亮绿灯
    } else {
        printf("TCP连接失败\r\n");
        LED_RED;    // 连接失败时亮红灯
    }
    
    Clear_Buffer();	
    
}

/*****************************************************
发送数据函数
*****************************************************/
void CSTX_4G_Senddata(uint8_t *len,uint8_t *data)//发送字符串数据
{
    const char* prefix = DEFAULT_DATA_PREFIX;
    const char* suffix = DEFAULT_DATA_SUFFIX;
    char send_buf[BUFLEN];
    memset(ATSTR,0,BUFLEN);
    size_t data_len;
    size_t prefix_len;
    size_t suffix_len;
    size_t total_len;
    data_len = strlen((const char*)data);
    prefix_len = strlen(prefix);
    suffix_len = strlen(suffix);
    total_len = prefix_len + data_len + suffix_len;
    if (total_len >= sizeof(send_buf)) {
        printf("发送数据过长，已拒绝发送，总长:%u，最大:%u\r\n", (unsigned)total_len, (unsigned)sizeof(send_buf)-1);
        return;
    }
    memcpy(send_buf, prefix, prefix_len);
    memcpy(send_buf + prefix_len, data, data_len);
    memcpy(send_buf + prefix_len + data_len, suffix, suffix_len);
    send_buf[total_len] = '\0';
    sprintf(ATSTR,"AT+QISEND=0,%u\r\n",(unsigned)total_len);
    Clear_Buffer();
    EC800M_UART_SendStr(ATSTR);
    Delay_ms(500);
    //等待模块反馈 >
    strx=strstr((const char*)EC800M_BUF.buf,(const char*)">");//模块反馈可以发送数据了
    while(strx==NULL)
    {
        errcount++;
        strx=strstr((const char*)EC800M_BUF.buf,(const char*)">");//模块反馈可以发送数据了
        extstrx=strstr((const char*)EC800M_BUF.buf,(const char*)"ERROR");//收到ERROR立即取消
        if(extstrx){
          printf("AT+QISEND收到ERROR，取消本次发送\r\n");
          EC800M_Reconnect();
          return;
        }
        if(errcount>100)     //防止死循环跳出
        {
            errcount = 0;
            break;
        }
    }
    
    if(strx==NULL){ EC800M_Reconnect(); return; }
    EC800M_UART_SendStr((char *)send_buf);//发送真正的数据（已带前后缀）
    Delay_ms(300);
    
    strx=strstr((const char*)EC800M_BUF.buf,(const char*)"SEND OK");//检查是否发送成功
    errcount=0;
    while(strx==NULL)
    {
        errcount++;
        strx=strstr((const char*)EC800M_BUF.buf,(const char*)"SEND OK");//检查是否发送成功
        Delay_ms(100);
        if(errcount>100)     //超时退出死循环 表示服务器连接失败
        {
            errcount = 0;
            break;
        }
    }  
    if(strx==NULL){ EC800M_Reconnect(); return; }
    Clear_Buffer();	
}

/*****************************************************
发送带自定义开头和结尾标记的数据函数
*****************************************************/
void CSTX_4G_SenddataWithPrefixSuffix(uint8_t *data, const char* prefix, const char* suffix)
{
    char send_buf[BUFLEN];
    memset(ATSTR,0,BUFLEN);
    size_t data_len;
    size_t prefix_len;
    size_t suffix_len;
    size_t total_len;
    
    // 如果未指定开头或结尾标记，则使用默认值
    if (prefix == NULL) {
        prefix = DEFAULT_DATA_PREFIX;
    }
    if (suffix == NULL) {
        suffix = DEFAULT_DATA_SUFFIX;
    }
    
    data_len = strlen((const char*)data);
    prefix_len = strlen(prefix);
    suffix_len = strlen(suffix);
    total_len = prefix_len + data_len + suffix_len;
    
    if (total_len >= sizeof(send_buf)) {
        printf("发送数据过长，已拒绝发送，总长:%u，最大:%u\r\n", (unsigned)total_len, (unsigned)sizeof(send_buf)-1);
        return;
    }
    
    memcpy(send_buf, prefix, prefix_len);
    memcpy(send_buf + prefix_len, data, data_len);
    memcpy(send_buf + prefix_len + data_len, suffix, suffix_len);
    send_buf[total_len] = '\0';
    
    sprintf(ATSTR,"AT+QISEND=0,%u\r\n",(unsigned)total_len);
    Clear_Buffer();
    EC800M_UART_SendStr(ATSTR);
    Delay_ms(500);
    
    //等待模块反馈 >
    strx=strstr((const char*)EC800M_BUF.buf,(const char*)">");//模块反馈可以发送数据了
    errcount = 0;
    while(strx==NULL)
    {
        errcount++;
        strx=strstr((const char*)EC800M_BUF.buf,(const char*)">");//模块反馈可以发送数据了
        extstrx=strstr((const char*)EC800M_BUF.buf,(const char*)"ERROR");//收到ERROR立即取消
        if(extstrx){
          printf("AT+QISEND收到ERROR，取消本次发送\r\n");
          EC800M_Reconnect();
          return;
        }
        if(errcount>100)     //防止死循环跳出
        {
            errcount = 0;
            break;
        }
        Delay_ms(10);
    }
    
    if(strx==NULL){ 
        printf("未收到模块发送数据的提示符 '>'\r\n");
        EC800M_Reconnect(); 
        return; 
    }
    
    EC800M_UART_SendStr((char *)send_buf);//发送真正的数据（已带前后缀）
    Delay_ms(300);
    
    strx=strstr((const char*)EC800M_BUF.buf,(const char*)"SEND OK");//检查是否发送成功
    errcount=0;
    while(strx==NULL)
    {
        errcount++;
        strx=strstr((const char*)EC800M_BUF.buf,(const char*)"SEND OK");//检查是否发送成功
        Delay_ms(100);
        if(errcount>100)     //超时退出死循环 表示服务器连接失败
        {
            errcount = 0;
            break;
        }
    }  
    
    if(strx==NULL){ 
        printf("数据发送失败，未收到SEND OK响应\r\n");
        EC800M_Reconnect(); 
        return; 
    }
    
    printf("数据发送成功: %s\r\n", send_buf);
    Clear_Buffer();	
}

/*****************************************************
发送DHT11温湿度数据函数
*****************************************************/
void CSTX_4G_SendDHT11Data(DHT11_Storage_Data_TypeDef *dht11_data)
{
    char dht11_json[128];
    char data_len[8];
    
    if(dht11_data == NULL)
    {
        printf("DHT11数据指针为空，无法发送\r\n");
        return;
    }
    
    // 构建JSON格式的DHT11数据
    sprintf(dht11_json, "{\"temp\":%d.%d,\"humi\":%d.%d}", 
            dht11_data->temp_int, dht11_data->temp_deci,
            dht11_data->humi_int, dht11_data->humi_deci);
    
    // 计算数据长度
    sprintf(data_len, "%d", strlen(dht11_json));
    
    printf("准备发送DHT11数据: %s (长度: %s字节)\r\n", dht11_json, data_len);
    
    // 发送数据（使用默认的开头和结尾标记）
    CSTX_4G_SenddataWithPrefixSuffix((uint8_t*)dht11_json, NULL, NULL);
    
    printf("DHT11数据发送完成\r\n");
}

/*****************************************************
收到服务器下发的数据就直接打印
*****************************************************/
void CSTX_4G_RECTCPData(void)
{
    strx=strstr((const char*)EC800M_BUF.buf,(const char*)"+QIURC");//返回+QIURC:，表明接收到TCP服务器发回的数据
		
    if(strx)
    {
        if (strstr((const char*)EC800M_BUF.buf,(const char*)"closed") || 
            strstr((const char*)EC800M_BUF.buf,(const char*)"CLOSED") || 
            strstr((const char*)EC800M_BUF.buf,(const char*)"pdpdeact"))
        {
            printf("检测到连接断开，执行重连\r\n");
            EC800M_Reconnect();
        }else if (strstr((const char*)EC800M_BUF.buf,(const char*)"recv")){
            //接收数据
            //printf("接收到原始数据：%s",(const char*)EC800M_BUF.buf);
            
            // 提取数据中的有效内容（去除开头和结尾标记）
            char *data_start = strstr((const char*)EC800M_BUF.buf, DEFAULT_DATA_PREFIX);
            if(data_start != NULL) {
                data_start += strlen(DEFAULT_DATA_PREFIX); // 跳过开头标记
                char *data_end = strstr(data_start, DEFAULT_DATA_SUFFIX);
                if(data_end != NULL) {
                    *data_end = '\0'; // 截断字符串
                    printf("接收到的有效数据: %s\r\n", data_start);
                    // 如果是心跳包则返回心跳包
                    if(strcmp(data_start, DEFAULT_DATA_HEARTBEAT) == 0){
											char datalen[8];
											CSTX_4G_Senddata((uint8_t*) datalen,(uint8_t*) DEFAULT_DATA_HEARTBEAT);
										}
                } else {
                    printf("未找到数据结尾标记\r\n");
                }
            } else {
                // 如果没有找到默认的开头标记，尝试直接处理数据
                printf("未找到数据开头标记，尝试直接处理数据\r\n");
                // 可以在这里添加对无标记数据的处理逻辑
            }
        }
        Clear_Buffer();         
    }
}

void EC800M_UART_send_byte(char data)
{
    while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
    USART_SendData(USART2, data);
}

void EC800M_UART_SendStr(char*SendBuf)
{
    while(*SendBuf)
    {
        while((USART2->SR&0X40)==0);
        USART2->DR = (u8) *SendBuf; 
        SendBuf++;
    }
    IWDG_ReloadCounter();//喂狗
}
